`timescale 1ns / 1ps

module prbs_testbench;

    // 测试信号定义
    reg        clk;
    reg        rst_n;
    reg        test_enable;
    reg [7:0]  test_seed;
    
    // DUT输出信号
    wire        prbs_out;
    wire [7:0]  lfsr_state;
    
    // 验证相关信号
    reg [63:0]  expected_sequence;  // 预期的64位PRBS序列
    reg [7:0]   expected_states [0:63]; // 预期的LFSR状态序列
    integer     bit_index;
    integer     error_count;
    integer     test_length;
    reg         verification_done;
    
    // 时钟生成 - 100MHz
    initial begin
        clk = 1'b0;
        forever #5 clk = ~clk;
    end
    
    // DUT实例化
    prbs_generator u_dut (
        .clk        (clk),
        .rst_n      (rst_n),
        .enable     (test_enable),
        .seed       (test_seed),
        .prbs_out   (prbs_out),
        .lfsr_state (lfsr_state)
    );
    
    // 理论计算：根据多项式x^8 + x^6 + x^5 + x^4 + 1和种子0x5A计算期望序列
    task calculate_expected_sequence;
        input [7:0] seed;
        output [63:0] sequence;
        output reg [7:0] states [0:63];
        
        reg [7:0] lfsr_temp;
        reg feedback_temp;
        integer i;
        
        begin
            lfsr_temp = (seed == 8'h00) ? 8'h01 : seed;
            states[0] = lfsr_temp;
            
            $display("=== 理论计算过程 ===");
            $display("多项式: x^8 + x^6 + x^5 + x^4 + 1");
            $display("种子: 0x%02X (%08b)", seed, seed);
            $display("抽头位置: [7,5,4,3,0]");
            $display("");
            
            for (i = 0; i < 64; i = i + 1) begin
                // 输出当前最高位
                sequence[63-i] = lfsr_temp[7];
                
                // 计算反馈
                feedback_temp = lfsr_temp[7] ^ lfsr_temp[5] ^ lfsr_temp[4] ^ lfsr_temp[3] ^ lfsr_temp[0];
                
                // 显示计算过程（前16步）
                if (i < 16) begin
                    $display("步骤%2d: 状态=%02X(%08b) 输出=%b 反馈=%b", 
                            i, lfsr_temp, lfsr_temp, lfsr_temp[7], feedback_temp);
                end
                
                // 左移并输入反馈
                lfsr_temp = {lfsr_temp[6:0], feedback_temp};
                
                // 保存下一个状态
                if (i < 63) states[i+1] = lfsr_temp;
            end
            
            $display("...");
            $display("期望序列(前32位): %032b", sequence[63:32]);
            $display("期望序列(后32位): %032b", sequence[31:0]);
        end
    endtask
    
    // 验证任务
    task verify_prbs_output;
        begin
            $display("=== 开始验证 ===");
            error_count = 0;
            bit_index = 0;
            verification_done = 0;
            test_length = 64;  // 验证64位
            
            // 等待一个时钟周期开始验证
            @(posedge clk);
            
            repeat(test_length) begin
                @(posedge clk);
                
                // 检查输出位
                if (prbs_out !== expected_sequence[63-bit_index]) begin
                    $display("ERROR: 位%2d 期望=%b 实际=%b", bit_index, expected_sequence[63-bit_index], prbs_out);
                    error_count = error_count + 1;
                end else begin
                    $display("PASS:  位%2d 期望=%b 实际=%b 状态=%02X", 
                            bit_index, expected_sequence[63-bit_index], prbs_out, lfsr_state);
                end
                
                // 检查LFSR状态
                if (lfsr_state !== expected_states[bit_index]) begin
                    $display("ERROR: 状态%2d 期望=%02X 实际=%02X", bit_index, expected_states[bit_index], lfsr_state);
                    error_count = error_count + 1;
                end
                
                bit_index = bit_index + 1;
            end
            
            verification_done = 1;
            
            $display("=== 验证结果 ===");
            $display("测试位数: %d", test_length);
            $display("错误数量: %d", error_count);
            $display("正确率: %.2f%%", (test_length - error_count) * 100.0 / test_length);
            
            if (error_count == 0) begin
                $display("*** 验证通过: PRBS生成器工作正确 ***");
            end else begin
                $display("*** 验证失败: 发现%d个错误 ***", error_count);
            end
        end
    endtask
    
    // 主测试流程
    initial begin
        $display("=== PRBS生成器验证测试 ===");
        
        // 初始化
        rst_n = 1'b0;
        test_enable = 1'b0;
        test_seed = 8'h5A;  // 测试种子
        
        // 计算期望序列
        calculate_expected_sequence(test_seed, expected_sequence, expected_states);
        
        // 复位时序
        #20;
        rst_n = 1'b1;
        #10;
        
        // 启动测试
        test_enable = 1'b1;
        
        // 开始验证
        verify_prbs_output();
        
        // 等待验证完成
        wait(verification_done);
        
        #100;
        $finish;
    end
    
    // 周期性检查（验证LFSR的255位周期特性）
    task check_periodicity;
        input integer period_length;
        reg [7:0] initial_state;
        reg [7:0] current_state;
        integer cycle_count;
        
        begin
            $display("=== 周期性验证 ===");
            initial_state = lfsr_state;
            cycle_count = 0;
            
            repeat(period_length + 10) begin  // 多运行几个周期确保检测到重复
                @(posedge clk);
                current_state = lfsr_state;
                cycle_count = cycle_count + 1;
                
                if (current_state == initial_state && cycle_count > 1) begin
                    $display("检测到周期: %d 位", cycle_count - 1);
                    $display("理论周期: %d 位", period_length);
                    if (cycle_count - 1 == period_length) begin
                        $display("*** 周期验证通过 ***");
                    end else begin
                        $display("*** 周期验证失败 ***");
                    end
                    return;
                end
            end
            
            $display("*** 未检测到预期周期 ***");
        end
    endtask
    
    // 辅助验证：检查序列的统计特性
    task analyze_sequence_properties;
        reg [255:0] full_sequence;
        integer ones_count, zeros_count;
        integer i;
        
        begin
            $display("=== 序列统计特性分析 ===");
            
            ones_count = 0;
            zeros_count = 0;
            
            // 收集完整周期的序列
            for (i = 0; i < 256; i = i + 1) begin
                @(posedge clk);
                full_sequence[255-i] = prbs_out;
                if (prbs_out) ones_count = ones_count + 1;
                else zeros_count = zeros_count + 1;
            end
            
            $display("总位数: %d", ones_count + zeros_count);
            $display("1的个数: %d (%.1f%%)", ones_count, ones_count * 100.0 / 256);
            $display("0的个数: %d (%.1f%%)", zeros_count, zeros_count * 100.0 / 256);
            
            // 平衡性检查
            if (ones_count == 128 && zeros_count == 127) begin  // 8位LFSR的理论值
                $display("*** 平衡性检查通过 ***");
            end else begin
                $display("*** 平衡性检查失败 ***");
                $display("期望: 1的个数=128, 0的个数=127");
            end
        end
    endtask
    
endmodule